package com.zznode.redsun.smartcrm.console.action;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import java.util.UUID;

import net.sf.json.JSONArray;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;
import net.sf.json.util.JSONUtils;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;

import com.zznode.redsun.commons.dto.GridFieldStyle;
import com.zznode.redsun.commons.utils.AbstractBaseAction;

/**
 * 数据导出
 * 
 * @author taoping
 * 
 */
@Controller
@Namespace("/export")
public class ExportAction extends AbstractBaseAction {

	private static final long serialVersionUID = 1L;
	private static final int EXCEL_WITHD_RATIO = 50;
	private static final Logger logger = LoggerFactory.getLogger(ExportAction.class);

	private InputStream inputStream;
	private String fileName;
	private String json;

	/**
	 * Excel导出
	 * 
	 * @return
	 */
	@Action(value = "exportExcel", results = { @Result(name = SUCCESS, type = JSON_TYPE, params = {
			JSON_PARAM_IGNOREHIERARCHY, "false", JSON_PARAM_INPROPERTIES, JSON_FLAG_MESSAGE }) })
	public String exportExcel() {
		JSONObject jsonData = JSONObject.fromObject(json);
		String gridName = jsonData.getString("fileName");
		JSONArray rowsData = jsonData.getJSONArray("rowsData");
		JSONArray colsTile = jsonData.getJSONArray("colsTile");

		if (JSONUtils.isNull(rowsData) && JSONUtils.isNull(colsTile)) {
			logger.warn("Receive the export data is null, file name : " + gridName);
			this.setJsonMessage("failed");
			return SUCCESS;
		}

		Workbook workbook = new HSSFWorkbook();
		Sheet sheet = workbook.createSheet(gridName);
		List<GridFieldStyle> fieldStyles = fillSheetHead(sheet, colsTile, createHeadCellStyle(workbook));
		fillSheetBody(sheet, rowsData, fieldStyles, createBodyCellStyle(workbook));
		setSheetCellWithd(sheet, fieldStyles);
		String fileId = generateExcelFile(workbook);
		this.setJsonMessage(fileId);

		return SUCCESS;
	}

	/**
	 * 文件下载
	 * 
	 * @return
	 */
	@Action(value = "download", results = { @Result(name = SUCCESS, type = "stream", params = { "contentType",
			"application/vnd.ms-excel", "contentDisposition", "attachment;filename=\"${fileName}\"", "bufferSize",
			"1024" }) })
	public String download() {
		String gridName = this.getParameter("fileName");
		String fileId = this.getParameter("fileId");
		if (StringUtils.hasText(fileId)) {
			this.fileName = StringUtils.hasText(gridName) ? gridName : fileId;
			String filePath = "/DBAutoCheck/download/" + fileId + ".xls";
			try {
				this.inputStream = new BufferedInputStream(new FileInputStream(new File(filePath)));
			} catch (FileNotFoundException ex) {
				logger.warn(ex.getMessage(), ex);
			}
		}
		return SUCCESS;
	}

	private String generateExcelFile(Workbook workbook) {
		String fileName = UUID.randomUUID().toString().replaceAll("-", "");
		String filePath = "/DBAutoCheck/download/" + fileName + ".xls";
		OutputStream output = null;
		try {
			output = new BufferedOutputStream(new FileOutputStream(new File(filePath)));
			workbook.write(output);
		} catch (IOException ex) {
			logger.warn(ex.getMessage(), ex);
		} finally {
			if (null != output) {
				try {
					output.close();
				} catch (IOException ex) {
					logger.warn(ex.getMessage(), ex);
				}
			}
		}
		return fileName;
	}

	private void setSheetCellWithd(Sheet sheet, List<GridFieldStyle> fieldStyles) {
		for (int i = 0; i < fieldStyles.size(); i++) {
			if (fieldStyles.get(i).isHidden()) {
				continue;
			} else if (fieldStyles.get(i).isAuto()) {
				sheet.autoSizeColumn(i);
			} else {
				sheet.setColumnWidth(i, fieldStyles.get(i).getWidth() * EXCEL_WITHD_RATIO);
			}
		}
	}

	private List<GridFieldStyle> fillSheetHead(Sheet sheet, JSONArray colsData, CellStyle headStyle) {
		Row row = sheet.createRow(0);
		int cellIndex = 0;
		List<GridFieldStyle> fieldStyles = new ArrayList<GridFieldStyle>();
		for (ListIterator<?> iterator = colsData.listIterator(); iterator.hasNext();) {
			JSONObject jsonField = (JSONObject) iterator.next();
			GridFieldStyle fieldStyle = (GridFieldStyle) JSONObject.toBean(jsonField, GridFieldStyle.class);
			if (!fieldStyle.isHidden()) {
				Cell cell = createCell(row, cellIndex, fieldStyle, fieldStyle.getTitle());
				cell.setCellStyle(headStyle);
				cellIndex++;
				fieldStyles.add(fieldStyle);
			}
		}
		return fieldStyles;
	}

	private void fillSheetBody(Sheet sheet, JSONArray rowsData, List<GridFieldStyle> fieldStyles, CellStyle bodyStyle) {
		int rowIndex = 1;
		for (ListIterator<?> iterator = rowsData.listIterator(); iterator.hasNext();) {
			JSONObject entry = (JSONObject) iterator.next();
			Row row = sheet.createRow(rowIndex);

			int cellIndex = 0;
			for (GridFieldStyle item : fieldStyles) {
				Cell cell = createCell(row, cellIndex, item, entry.get(item.getField()));
				cell.setCellStyle(bodyStyle);
				cellIndex++;
			}
			rowIndex++;
		}
	}

	private Cell createCell(Row row, int index, GridFieldStyle fieldStyle, Object value) {
		Cell cell = row.createCell(index);

		if (null == value || JSONNull.getInstance().equals(value)) {
			return cell;
		} else if (value instanceof Date) {
			DateFormat dateFormat = SimpleDateFormat.getDateTimeInstance();
			cell.setCellValue(dateFormat.format(value));
		} else if (value instanceof Calendar) {
			DateFormat dateFormat = SimpleDateFormat.getDateTimeInstance();
			cell.setCellValue(dateFormat.format(value));
		} else if (value instanceof Boolean) {
			cell.setCellValue((Boolean) value);
		} else if (value instanceof String) {
			cell.setCellValue((String) value);
		} else {
			cell.setCellValue(value.toString());
		}

		return cell;
	}

	private CellStyle createHeadCellStyle(Workbook workbook) {
		CellStyle style = workbook.createCellStyle();
		style.setAlignment(CellStyle.ALIGN_CENTER);
		style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
		style.setFillBackgroundColor(IndexedColors.PALE_BLUE.getIndex());
		// style.setFillPattern(CellStyle.SOLID_FOREGROUND);

		Font font = workbook.createFont();
		font.setBoldweight(Font.BOLDWEIGHT_BOLD);

		style.setFont(font);
		return style;
	}

	private CellStyle createBodyCellStyle(Workbook workbook) {
		CellStyle style = workbook.createCellStyle();
		style.setAlignment(CellStyle.ALIGN_CENTER);
		style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);

		Font font = workbook.createFont();

		style.setFont(font);
		style.setWrapText(false);
		return style;
	}

	public InputStream getInputStream() {
		return inputStream;
	}

	/**
	 * 导出文件名
	 * 
	 * @return
	 */
	public String getFileName() {
		try {
			return new String(fileName.getBytes(), "ISO8859-1");
		} catch (UnsupportedEncodingException e) {
			logger.warn(e.getMessage(), e);
			return String.valueOf(Calendar.getInstance().getTimeInMillis());
		}
	}

	public String getJson() {
		return json;
	}

	public void setJson(String json) {
		this.json = json;
	}

}
